// Dedicated to the public domain by Christopher Diggins
// http://www.cdiggins.com

#ifndef YARD_HERON_GRAMMAR_HPP
#define YARD_HERON_GRAMMAR_HPP

#include "yard_shared_grammar.hpp"

namespace heron_grammar
{
	using namespace shared_grammar;

	struct Expr;
    struct TypeExpr;
    struct SimpleExpr;
    struct Statement;
    struct StatementList;
    struct CodeBlock;
	struct Annotation;
	struct Class;

	struct METHODS : Keyword<CharSeq<'m','e','t','h','o','d','s'> > { };
	struct INHERITS : Keyword<CharSeq<'i','n','h','e','r','i','t','s'> > { };
	struct IMPLEMENTS : Keyword<CharSeq<'i','m','p','l','e','m','e','n','t','s'> > { };
	struct FIELDS : Keyword<CharSeq<'f','i','e','l','d','s'> > { };

	struct AnnotationGroup :
        StoreCommaList<CharTok<'('>, Annotation, CharTok<')'> > { };

	struct Annotation : 
		Star<Seq<Or<Store<Name>, Store<Literal>, Store<AnnotationGroup> >, WS> > { };

	struct Annotations :
        StoreCommaList<CharTok<'['>, Annotation, CharTok<']'> > { };

    struct TypeArgs :
        StoreCommaList<CharTok<'<'>, TypeExpr, CharTok<'>'> > { };

    struct TypeExpr : 
        Seq<Store<Name>, WS, Opt<Store<TypeArgs> > > { };

    struct TypeDecl :
        NoFailSeq<CharTok<':'>, Store<TypeExpr> > { };

    struct Arg :
        Seq<Store<Name>, WS, Opt<TypeDecl> > { };

    struct ArgList :        
        StoreCommaList<CharTok<'('>, Arg, CharTok<')'> > { };

    struct AnonFxn :
        Seq<FUNCTION, NoFailSeq<Store<ArgList>, Opt<TypeDecl>, Opt<WS>, Store<CodeBlock> > > { };

    struct DelExpr :
        NoFailSeq<DELETE, Store<Expr> > { };

    struct ParanthesizedExpr :
        NoFailSeq<CharTok<'('>, Star<Seq<Store<Expr>, Opt<CharTok<','> > > >, CharTok<')'> > { };

    struct BracketedExpr :
        NoFailSeq<CharTok<'['>, Store<Expr>, CharTok<']'> > { };

    struct NewExpr :
        NoFailSeq<NEW, Store<TypeExpr>, Store<ParanthesizedExpr> > { };

    struct SimpleExpr :
        Or<Store<NewExpr>,
            Store<DelExpr>,
            Seq<Store<Name>, WS>,
            Store<Literal>,
            Store<AnonFxn>,
            Store<ParanthesizedExpr>,
            Store<BracketedExpr>
        > { };

    // Note that unlike typical grammar designs, I have delayed 
    // prcedence handling to the AST processing mechanism.
	// This makes the grammar much simpler
    struct Expr :
        Plus<Store<SimpleExpr> > { };

	struct Eos : 
        CharTok<';'> { };

	struct Initializer :
        Seq<CharTok<'='>, Store<Expr> > { };

    struct CodeBlock :
        NoFailSeq<CharTok<'{'>, StatementList, Finao<CharTok<'}'> > > { };

    struct VarDecl :
        NoFailSeq<VAR, Store<Name>, WS, Opt<TypeDecl>, Opt<Initializer>, Eos > { };

    struct StaticDecl :
        NoFailSeq<STATIC, Store<Name>, WS, Opt<TypeDecl>, Opt<Initializer>, Eos > { };

    struct ElseStatement :
        NoFailSeq<ELSE, Store<Statement> > { };

    struct IfStatement :
        NoFailSeq<IF, Paranthesized<Store<Expr> >, Store<Statement>, Opt<ElseStatement> > { };

    struct ForEachStatement :
        NoFailSeq<FOREACH, CharTok<'('>, VAR, Store<Name>, WS, Opt<TypeDecl>, 
            IN, Store<Expr>, CharTok<')'>, Store<Statement> > { };

    struct ForStatement :
        NoFailSeq<FOR, 
			CharTok<'('>, 
			Seq<VAR, Store<Name>, WS, Opt<TypeDecl>, Opt<Initializer> >,
			Eos,
			Store<Expr>, 
			Eos,
			Store<Expr>,
			CharTok<')'>, 
			Store<Statement> 
		> { };

    struct ExprStatement :
        Seq<Store<Expr>, Eos> { };

    struct ReturnStatement :
        NoFailSeq<RETURN, Store<Expr>, Eos> { };    

    struct BreakStatement :
        NoFailSeq<BREAK, Eos> { };    

    struct CaseStatement :
        NoFailSeq<CASE, Paranthesized<Store<Expr> >, Store<CodeBlock> > { };

    struct DefaultStatement :
        NoFailSeq<DEFAULT, Store<CodeBlock> > { };

    struct SwitchStatement :
        NoFailSeq<SWITCH, Paranthesized<Store<Expr> >, CharTok<'{'>, Star<Store<CaseStatement> >, 
            Opt<Store<DefaultStatement> >, CharTok<'}'> > { };

    struct WhileStatement :
        NoFailSeq<WHILE, Paranthesized<Store<Expr> >, Store<Statement> > { };
    
    struct EmptyStatement :
        Eos { };

	struct ImportStatement :
		NoFailSeq<IMPORT, Store<Name>, WS, Eos> { };

    struct Function :
        NoFailSeq<FUNCTION, Store<Name>, WS, Store<ArgList>, Opt<TypeDecl>, Store<CodeBlock> > { };    

    struct Statement :
        Or<
            Or<
                Store<CodeBlock>,
                Store<VarDecl>,
                Store<IfStatement>,
                Store<SwitchStatement>,
                Store<ForEachStatement>,
                Store<ForStatement>,
                Store<WhileStatement>
            >,
            Or<
				Store<Function>,
				Store<StaticDecl>,
				Store<ImportStatement>,
                Store<BreakStatement>,
                Store<ReturnStatement>,
                Store<ExprStatement>,
                Store<EmptyStatement>
            >
       > { };

    struct StatementList :
        Star<Store<Statement> > { };
	
	struct Module :
		NoFailSeq<MODULE, Store<Name>, WS, CharTok<'{'>, Star<Store<Class> >, CharTok<'}'> > { };
		// NoFailSeq<MODULE, Store<Name>, WS, Store<CodeBlock> > { };

	struct InheritedType :
		NoFailSeq<Store<TypeExpr>, Eos>  { };

	struct ImplementedType :
		NoFailSeq<Store<TypeExpr>, Eos>  { };
	
    struct Method :
        NoFailSeq<Store<Name>, WS, Store<ArgList>, Opt<TypeDecl>, Opt<WS>, Store<CodeBlock> > { };

	struct Field :
		NoFailSeq<Store<Name>, WS, Opt<TypeDecl>, Eos> { };

	struct Inherits :
		NoFailSeq<INHERITS, CharTok<'{'>, Star<InheritedType>, CharTok<'}'> > { };

	struct Implements :
		NoFailSeq<IMPLEMENTS, CharTok<'{'>, Star<ImplementedType>, CharTok<'}'> > { };

	struct Methods :
		NoFailSeq<METHODS, CharTok<'{'>, Star<Store<Method> >, CharTok<'}'> > { };

	struct Fields :
		NoFailSeq<FIELDS, CharTok<'{'>, Star<Store<Field> >, CharTok<'}'> > { };

	struct Class :
		NoFailSeq<CLASS, 
			Store<Name>, WS, CharTok<'{'>, Opt<Store<Inherits> >, 
			Opt<Store<Implements> >, Opt<Store<Methods> >, Opt<Store<Fields> >, CharTok<'}'>  > { };

	struct Program :
		NoFailSeq<PROGRAM, Store<Name>, WS, Store<CodeBlock> > { };

	struct HeronFile :
		Seq<WS, Store<Module> > { };
	
	// , Store<Program>, Store<StatementList> >, Finao<EndOfInput> > { };    
}

#endif
